/**
 * @file	
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */
/*********************************************************************
 * INCLUDES
 */
#include "bcomdef.h"
#include "OSAL.h"
#include "osal_cbTimer.h"
#include "osal_snv.h"
#include "hci_tl.h"
#include "gap.h"

#include "observer.h"

/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */

// Task ID
static uint8 gapObserverRoleTaskId;

// App callbacks
static gapObserverRoleCB_t *pGapObserverRoleCB;

/*********************************************************************
 * Profile Parameters - reference GAPCENTRALROLE_PROFILE_PARAMETERS for
 * descriptions
 */

static uint8  gapObserverRoleBdAddr[B_ADDR_LEN];
static uint8  gapObserverRoleMaxScanRes = 0;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void gapObserverRole_ProcessOSALMsg( osal_event_hdr_t *pMsg );
static void gapObserverRole_ProcessGAPMsg( gapEventHdr_t *pMsg );

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/**
 * @brief   Start the device in Observer role.  This function is typically
 *          called once during system startup.
 *
 * Public function defined in observer.h.
 */
bStatus_t GAPObserverRole_StartDevice( gapObserverRoleCB_t *pAppCallbacks )
{
  if ( pAppCallbacks )
  {
    pGapObserverRoleCB = pAppCallbacks;
  }

  return GAP_DeviceInit( gapObserverRoleTaskId, GAP_PROFILE_OBSERVER,
                         gapObserverRoleMaxScanRes, NULL, NULL, NULL );
}

/**
 * @brief   Set a parameter in the Observer Profile.
 *
 * Public function defined in observer.h.
 */
bStatus_t GAPObserverRole_SetParameter( uint16 param, uint8 len, void *pValue )
{
  bStatus_t ret = SUCCESS;

  switch ( param )
  {
    case GAPOBSERVERROLE_MAX_SCAN_RES:
      if ( len == sizeof ( uint8 ) )
      {
        gapObserverRoleMaxScanRes = *((uint8*)pValue);
      }
      else
      {
        ret = bleInvalidRange;
      }
      break;

    default:
      ret = INVALIDPARAMETER;
      break;
  }

  return ret;
}

/**
 * @brief   Get a parameter in the Observer Profile.
 *
 * Public function defined in observer.h.
 */
bStatus_t GAPObserverRole_GetParameter( uint16 param, void *pValue )
{
  bStatus_t ret = SUCCESS;

  switch ( param )
  {
    case GAPOBSERVERROLE_BD_ADDR:
      VOID osal_memcpy( pValue, gapObserverRoleBdAddr, B_ADDR_LEN ) ;
      break;

    case GAPOBSERVERROLE_MAX_SCAN_RES:
      *((uint8*)pValue) = gapObserverRoleMaxScanRes;
      break;

    default:
      ret = INVALIDPARAMETER;
      break;
  }

  return ret;
}

/**
 * @brief   Start a device discovery scan.
 *
 * Public function defined in observer.h.
 */
bStatus_t GAPObserverRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList )
{
  gapDevDiscReq_t params;

  params.taskID = gapObserverRoleTaskId;
  params.mode = mode;
  params.activeScan = activeScan;
  params.whiteList = whiteList;

  return GAP_DeviceDiscoveryRequest( &params );
}

/**
 * @brief   Cancel a device discovery scan.
 *
 * Public function defined in observer.h.
 */
bStatus_t GAPObserverRole_CancelDiscovery( void )
{
  return GAP_DeviceDiscoveryCancel( gapObserverRoleTaskId );
}

/**
 * @brief   Observer Profile Task initialization function.
 *
 * @param   taskId - Task ID.
 *
 * @return  void
 */
void GAPObserverRole_Init( uint8 taskId )
{
  gapObserverRoleTaskId = taskId;

  // Register for HCI messages (for RSSI)
  GAP_RegisterForHCIMsgs( taskId );
}

/**
 * @brief   Observer Profile Task event processing function.
 *
 * @param   taskId - Task ID
 * @param   events - Events.
 *
 * @return  events not processed
 */
uint16 GAPObserverRole_ProcessEvent( uint8 taskId, uint16 events )
{
  if ( events & SYS_EVENT_MSG )
  {
    uint8 *pMsg;

    if ( (pMsg = osal_msg_receive( gapObserverRoleTaskId )) != NULL )
    {
      gapObserverRole_ProcessOSALMsg( (osal_event_hdr_t *) pMsg );

      // Release the OSAL message
      VOID osal_msg_deallocate( pMsg );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  // Discard unknown events
  return 0;
}

/*********************************************************************
 * @fn      gapObserverRole_ProcessOSALMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void gapObserverRole_ProcessOSALMsg( osal_event_hdr_t *pMsg )
{
  switch ( pMsg->event )
  {
    case HCI_GAP_EVENT_EVENT:
      if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE )
      {
        //hciEvt_CmdComplete_t *pPkt = (hciEvt_CmdComplete_t *) pMsg;
      }
      break;

    case GAP_MSG_EVENT:
      gapObserverRole_ProcessGAPMsg( (gapEventHdr_t *) pMsg );
      break;

    default:
      break;
  }
}

/*********************************************************************
 * @fn      gapObserverRole_ProcessGAPMsg
 *
 * @brief   Process an incoming task message from GAP.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void gapObserverRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
  switch ( pMsg->opcode )
  {
    case GAP_DEVICE_INIT_DONE_EVENT:
      {
        gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *) pMsg;

        if ( pPkt->hdr.status == SUCCESS )
        {
          // Save off the information
          VOID osal_memcpy( gapObserverRoleBdAddr, pPkt->devAddr, B_ADDR_LEN );
        }
      }
      break;

    default:
      break;
  }

  // Pass event to app
  if ( pGapObserverRoleCB && pGapObserverRoleCB->eventCB )
  {
    pGapObserverRoleCB->eventCB( (gapObserverRoleEvent_t *) pMsg );
  }
}

/*********************************************************************
*********************************************************************/
